package com.pmcc.utils;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.FatalBeanException;
import org.springframework.util.Assert;

import javax.servlet.http.HttpServletRequest;
import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.io.BufferedReader;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.math.BigDecimal;
import java.util.*;


/**
 * 对象的属性复制
 *
 * @author wp
 */
public abstract class BeanUtils extends org.springframework.beans.BeanUtils {


    @SuppressWarnings("unused")
    public static String getRequestPayload(HttpServletRequest req) {
        StringBuilder sb = new StringBuilder();
        try {
            BufferedReader reader = req.getReader();
            char[] buff = new char[1024];
            int len;
            while ((len = reader.read(buff)) != -1) {
                sb.append(buff, 0, len);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        String result = sb.toString();
        if (result.startsWith("{"))
            result = '[' + result + ']';// to Array
        return result;
    }


    /**
     * 从request中获取不为空的数据放到持久对象中
     *
     * @param bean
     * @param request
     */
    public static void setBeanData(Object bean, HttpServletRequest request) {
        Class clazz = bean.getClass();
        Method ms[] = clazz.getDeclaredMethods();
        String mname;
        String field;
        String fieldType;

        Map map = request.getParameterMap();
        Set keSet = map.entrySet();
        for (Iterator itr = keSet.iterator(); itr.hasNext(); ) {
            String value = "";
            Map.Entry me = (Map.Entry) itr.next();
            Object ok = me.getKey();
            Object ov = me.getValue();
            String[] ovvalue = new String[1];
            if (ov instanceof String[]) {
                ovvalue = (String[]) ov;
            } else {
                ovvalue[0] = ov.toString();
            }

            for (int k = 0; k < ovvalue.length; k++) {
                value = ovvalue[k];
            }
            for (Method m : ms) {
                mname = m.getName();
                if (!mname.startsWith("set") || ArrayUtils.isEmpty(m.getParameterTypes())) {
                    continue;
                }
                try {
                    field = mname.toLowerCase().charAt(3) + mname.substring(4, mname.length());
                    if (ok.equals(field)) {
//						if (StringUtils.isEmpty(value)) {
//							m.invoke(bean, value);
//							continue;
//						}
                        fieldType = m.getParameterTypes()[0].getName();
                        // 以下可以确认value为String类型
                        if (String.class.getName().equals(fieldType)) {
                            if (StringUtils.isEmpty(value)) {
                                m.invoke(bean, (String) null);
                            } else {
                                m.invoke(bean, (String) value);
                            }
                        } else if (Integer.class.getName().equals(fieldType) && NumberUtils.isDigits((String) value)) {
                            if (StringUtils.isEmpty(value)) {
                                m.invoke(bean, (Integer) null);
                            } else {
                                m.invoke(bean, Integer.valueOf((String) value));
                            }

                        } else if (Short.class.getName().equals(fieldType) && NumberUtils.isDigits((String) value)) {
                            if (StringUtils.isEmpty(value)) {
                                m.invoke(bean, (Short) null);
                            } else {
                                m.invoke(bean, Short.valueOf((String) value));
                            }
                        } else if (Float.class.getName().equals(fieldType) && NumberUtils.isNumber((String) value)) {
                            if (StringUtils.isEmpty(value)) {
                                m.invoke(bean, (Float) null);
                            } else {
                                m.invoke(bean, Float.valueOf((String) value));
                            }

                        } else if (Double.class.getName().equals(fieldType) && NumberUtils.isNumber((String) value)) {
                            if (StringUtils.isEmpty(value)) {
                                m.invoke(bean, (Double) null);
                            } else {
                                m.invoke(bean, Double.valueOf((String) value));
                            }

                        } else if (Long.class.getName().equals(fieldType) && NumberUtils.isNumber((String) value)) {
                            if (StringUtils.isEmpty(value)) {
                                m.invoke(bean, (Long) null);
                            } else {
                                m.invoke(bean, Long.valueOf((String) value));
                            }

                        } else if (Date.class.getName().equals(fieldType)) {
                            if (StringUtils.isEmpty(value)) {
                                m.invoke(bean, (Date) null);
                            } else {
                                m.invoke(bean, DateUtils.parseDate((String) value, "yyyy-MM-dd", "yyyy-MM-dd HH:mm:ss"));
                            }

                        } else if (BigDecimal.class.getName().equals(fieldType)) {
                            if (StringUtils.isEmpty(value)) {
                                m.invoke(bean, (BigDecimal) null);
                            } else {
                                m.invoke(bean, BigDecimal.valueOf(Double.valueOf(value)));
                            }

                        } else {
                            m.invoke(bean, value);
                        }
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                    continue;
                }
            }

        }
    }


    public static <T> T toBean(Class<T> clazz, Map map) {
        T obj = null;
        try {
            BeanInfo beanInfo = Introspector.getBeanInfo(clazz);
            obj = clazz.newInstance(); // 创建 JavaBean 对象

            // 给 JavaBean 对象的属性赋值
            PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
            for (int i = 0; i < propertyDescriptors.length; i++) {
                PropertyDescriptor descriptor = propertyDescriptors[i];
                String propertyName = descriptor.getName();
                if (map.containsKey(propertyName)) {
                    // 下面一句可以 try 起来，这样当一个属性赋值失败的时候就不会影响其他属性赋值。
                    Object value = map.get(propertyName);
                    if ("".equals(value)) {
                        value = null;
                    }
                    Object[] args = new Object[1];
                    args[0] = value;
                    try {
                        descriptor.getWriteMethod().invoke(obj, args);
                    } catch (InvocationTargetException e) {
                        System.out.println("字段映射失败");
                    }
                }
            }
        } catch (IllegalAccessException e) {
            System.out.println("实例化 JavaBean 失败");
        } catch (IntrospectionException e) {
            System.out.println("分析类属性失败");
        } catch (IllegalArgumentException e) {
            System.out.println("映射错误");
        } catch (InstantiationException e) {
            System.out.println("实例化 JavaBean 失败");
        }
        return (T) obj;
    }


    public static void setBeanData(Object bean, Map<String, String> map) {
        Class clazz = bean.getClass();
        Method ms[] = clazz.getDeclaredMethods();
        String mname;
        String field;
        String fieldType;

        Set keSet = map.entrySet();
        for (Iterator itr = keSet.iterator(); itr.hasNext(); ) {
            String value = "";
            Object ok = null;
            Object ov = null;
            String[] ovvalue = new String[1];
            try {
                Map.Entry me = (Map.Entry) itr.next();
                ok = me.getKey();
                ov = me.getValue();
                if (ov instanceof String[]) {
                    ovvalue = (String[]) ov;
                } else {
                    ovvalue[0] = ov.toString();
                }
            } catch (Exception e) {
                continue;
            }

            for (int k = 0; k < ovvalue.length; k++) {
                value = ovvalue[k];
            }
            for (Method m : ms) {
                mname = m.getName();
                if (!mname.startsWith("set") || ArrayUtils.isEmpty(m.getParameterTypes())) {
                    continue;
                }
                try {
                    field = mname.toLowerCase().charAt(3) + mname.substring(4, mname.length());
                    if (ok.equals(field)) {
//						if (StringUtils.isEmpty(value)) {
//							m.invoke(bean, value);
//							continue;
//						}
                        fieldType = m.getParameterTypes()[0].getName();
                        // 以下可以确认value为String类型
                        if (String.class.getName().equals(fieldType)) {
                            if (StringUtils.isEmpty(value)) {
                                m.invoke(bean, (String) null);
                                break;
                            } else {
                                m.invoke(bean, (String) value);
                                break;
                            }
                        } else if (Integer.class.getName().equals(fieldType) && NumberUtils.isDigits((String) value)) {
                            if (StringUtils.isEmpty(value)) {
                                m.invoke(bean, (Integer) null);
                                break;
                            } else {
                                m.invoke(bean, Integer.valueOf((String) value));
                                break;
                            }

                        } else if (Short.class.getName().equals(fieldType) && NumberUtils.isDigits((String) value)) {
                            if (StringUtils.isEmpty(value)) {
                                m.invoke(bean, (Short) null);
                            } else {
                                m.invoke(bean, Short.valueOf((String) value));
                            }
                        } else if (Float.class.getName().equals(fieldType) && NumberUtils.isNumber((String) value)) {
                            if (StringUtils.isEmpty(value)) {
                                m.invoke(bean, (Float) null);
                            } else {
                                m.invoke(bean, Float.valueOf((String) value));
                            }

                        } else if (Double.class.getName().equals(fieldType) && NumberUtils.isNumber((String) value)) {
                            if (StringUtils.isEmpty(value)) {
                                m.invoke(bean, (Double) null);
                            } else {
                                m.invoke(bean, Double.valueOf((String) value));
                            }

                        } else if (Long.class.getName().equals(fieldType) && NumberUtils.isNumber((String) value)) {
                            if (StringUtils.isEmpty(value)) {
                                m.invoke(bean, (Long) null);
                            } else {
                                m.invoke(bean, Long.valueOf((String) value));
                            }

                        } else if (Date.class.getName().equals(fieldType)) {
                            if (StringUtils.isEmpty(value)) {
                                m.invoke(bean, (Date) null);
                            } else {
                                m.invoke(bean, DateUtils.parseDate((String) value, "yyyy-MM-dd", "yyyy-MM-dd HH:mm:ss"));
                            }

                        } else if (BigDecimal.class.getName().equals(fieldType)) {
                            if (StringUtils.isEmpty(value)) {
                                m.invoke(bean, (BigDecimal) null);
                            } else {
                                m.invoke(bean, BigDecimal.valueOf(Double.valueOf(value)));
                            }
                        } else {
                            if (StringUtils.isEmpty(value)) {
                                m.invoke(bean, null);
                            } else {
                                m.invoke(bean, value);
                            }
                        }
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                    continue;
                }
            }

        }
    }

    // Map --> Bean 1: 利用Introspector,PropertyDescriptor实现 Map --> Bean  
    public static void transMap2Bean(Map<String, Object> map, Object obj) {
        try {
            BeanInfo beanInfo = Introspector.getBeanInfo(obj.getClass());
            PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();

            for (PropertyDescriptor property : propertyDescriptors) {
                String key = property.getName();

                if (map.containsKey(key)) {
                    Object value = map.get(key);
                    // 得到property对应的setter方法  
                    Method setter = property.getWriteMethod();
                    setter.invoke(obj, value);
                }
            }
        } catch (Exception e) {
            System.out.println("transMap2Bean Error " + e);
        }
        return;
    }

    // Bean --> Map 1: 利用Introspector和PropertyDescriptor 将Bean --> Map  
    public static Map<String, Object> transBean2Map(Object obj) {
        if (obj == null) {
            return null;
        }
        Map<String, Object> map = new HashMap<String, Object>();
        try {
            BeanInfo beanInfo = Introspector.getBeanInfo(obj.getClass());
            PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
            for (PropertyDescriptor property : propertyDescriptors) {
                String key = property.getName();

                // 过滤class属性  
                if (!key.equals("class")) {
                    // 得到property对应的getter方法  
                    Method getter = property.getReadMethod();
                    Object value = getter.invoke(obj);

                    map.put(key, value);
                }
            }
        } catch (Exception e) {
            System.out.println("transBean2Map Error " + e);
        }
        return map;
    }

    // Bean --> Map 1: 利用Introspector和PropertyDescriptor 将Bean --> Map
    public static Map<String, Object> transBean2MapNoNull(Object obj) {
        if (obj == null) {
            return null;
        }
        Map<String, Object> map = new HashMap<String, Object>();
        try {
            BeanInfo beanInfo = Introspector.getBeanInfo(obj.getClass());
            PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
            for (PropertyDescriptor property : propertyDescriptors) {
                String key = property.getName();

                // 过滤class属性
                if (!key.equals("class")) {
                    // 得到property对应的getter方法
                    Method getter = property.getReadMethod();
                    Object value = getter.invoke(obj);
                    if (value != null) {
                        map.put(key, value);
                    }
                }
            }
        } catch (Exception e) {
            System.out.println("transBean2Map Error " + e);
        }
        return map;
    }

}
